import math

import numpy as np
import matplotlib.pyplot as plt

"""
用时间相关的学习率取代，增加了控制优化算法收敛的复杂性
动态学习率最大的两个问题：
1、衰减速度太快，过早停止优化
2、衰减速度太慢，会在优化上浪费时间

基本策略有：
1、分段常数（在不同时间段，给定不同的常数）: 需要降低学习率
2、指数衰减 （使用e的负指数（t 时间）幂  e^-t）：算法收敛过早停止
3、多项式衰减 （(a * t + 1)^α）：最优解，适合凸优化
"""

w1 = np.linspace(-1, 1, 30)
w2 = np.linspace(-0.8, 0.8, 30)
e = w1 ** 2 + 2 * w2 ** 2

current_w1 = -1
current_w2 = -0.8
# 学习率为常数
lr = 0.1
# 时间
t = 1
# 学习率 分别取 0.2、0.02、0.9 学习图线会呈现不一样的状态
num_epochs = 100
predict_w = []
for i in range(num_epochs):
    predict_w.append([current_w1, current_w2])
    slope1 = 2 * current_w1
    slope2 = 4 * current_w2
    # 梯度噪点
    slope1 += np.random.random() * 1
    slope2 += np.random.random() * 1
    # 动态学习率-指数衰减
    # lr = math.exp(-0.8 * t)
    # t += 1
    # 动态学习率-多项式衰减
    lr = (1 + 3 * t) ** (-0.5)
    t += 1
    # SGD 小固定值 * 斜率
    current_w1 -= lr * slope1
    current_w2 -= lr * slope2

predict_w = np.array(predict_w)
x1, x2 = np.meshgrid(w1, w2, indexing='ij')
plt.contour(x1, x2, x1 ** 2 + 2 * x2 ** 2, colors="#1f77b4")
plt.plot(predict_w[:, 0], predict_w[:, 1], 'ro-')
plt.show()
